<!DOCTYPE html>
<html lang="en"><head>
    <title>CZH-DEV BLOG</title>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta content="utf-8" http-equiv="encoding">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="format-detection" content="telephone=no" />
    <meta name="theme-color" content="#000084" />
    <link rel="icon" href="https://czh-dev.gitee.io/czh-blog.gitee.io//favicon.ico">
    <link rel="canonical" href="https://czh-dev.gitee.io/czh-blog.gitee.io/">
    
    
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="navbar-inner">
        <div class="container">
            <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"></button>
            <a class="brand" href="https://czh-dev.gitee.io/czh-blog.gitee.io/">CZH-DEV BLOG</a>
            <div class="nav-collapse collapse">
                <ul class="nav">
                    
                    
                        
                            <li>
                                <a href="/czh-blog.gitee.io/about/">
                                    
                                    <span>About</span>
                                </a>
                            </li>
                        
                    
                        
                            <li>
                                <a href="/czh-blog.gitee.io/post/">
                                    
                                    <span>All posts</span>
                                </a>
                            </li>
                        
                    
                        
                            <li>
                                <a href="/czh-blog.gitee.io/ebook/">
                                    
                                    <span>Resource</span>
                                </a>
                            </li>
                        
                    
                </ul>
            </div>
        </div>
    </div>
</nav><div id="content" class="container">
<div style="display: flex;">
  <div class="row-fluid navmargin">
    <div class="page-header">
      <h1>Spring Cloud Alibaba（Ⅵ） - Sat, Feb 11, 2023</h1>
    </div>
    <p class="lead"></p>
    <h1 id="第六章-服务熔断降级-sentinel">第六章 服务熔断降级 Sentinel</h1>
<h2 id="61-高并发带来的问题">6.1 高并发带来的问题</h2>
<p>​	在微服务架构中，我们将业务拆分成一个个的服务，服务与服务之间可以相互调用，但是由于网络原因或者自身的原因，服务并不能保证服务的100%可用，如果单个服务出现问题，调用这个服务就会出现网络延迟，此时若有大量的网络涌入，会形成任务堆积，最终导致服务瘫痪。</p>
<p><strong>接下来，我们来模拟一个高并发的场景</strong></p>
<ol>
<li>
<p>在订单服务中新建SentinelController.java</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SentinelController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/sentinel1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">sentinel1</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//模拟一次网络延时
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            TimeUnit<span style="color:#f92672">.</span><span style="color:#a6e22e">SECONDS</span><span style="color:#f92672">.</span><span style="color:#a6e22e">sleep</span><span style="color:#f92672">(</span>1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>InterruptedException e<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            e<span style="color:#f92672">.</span><span style="color:#a6e22e">printStackTrace</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;sentinel1&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/sentinel2&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">sentinel2</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;测试高并发下的问题&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>修改配置文件中tomcat的并发数</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">server</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">port</span>: <span style="color:#ae81ff">8091</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">tomcat</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">threads</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">max</span>: <span style="color:#ae81ff">10</span> <span style="color:#75715e">#tomcat的最大并发值修改为10</span>
</span></span></code></pre></div></li>
<li>
<p>接下来使用压测工具,对请求进行压力测试</p>
<p>下载地址https://jmeter.apache.org/</p>
<ul>
<li>
<p>第一步：修改配置，并启动软件</p>
<p>进入bin目录,修改jmeter.properties文件中的语言支持为language=zh_CN，然后点击jmeter.bat</p>
<p>启动软件。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455986.png" alt="image-20201029115836172"></strong></p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455304.png" alt="image-20201029115935101"></strong></p>
</li>
<li>
<p>第二步：添加线程组</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455830.png" alt="image-20201029120234401"></strong></p>
</li>
<li>
<p>第三步：配置线程并发数</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455869.png" alt="image-20201029124003847"></strong></p>
</li>
<li>
<p>第四步：添加Http请求</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455654.png" alt="image-20201029122851926"></strong></p>
</li>
<li>
<p>第五步：配置取样，并启动测试</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455504.png" alt="image-20201029123042028"></strong></p>
</li>
</ul>
<p>第六步：访问 http://localhost:8091/sentinel2 观察结果</p>
<p><strong>结论</strong>:此时会发现, 由于sentinel1方法囤积了大量请求, 导致sentinel2方法的访问出现了问题，这就是服务雪</p>
<p>崩的雏形。</p>
<h2 id="62-服务器雪崩效应">6.2 服务器雪崩效应</h2>
<p>​	在分布式系统中,由于网络原因或自身的原因,服务一般无法保证 100% 可用。如果一个服务出现了问题，调用这个服务就会出现线程阻塞的情况，此时若有大量的请求涌入，就会出现多条线程阻塞等待，进而导致服务瘫痪。</p>
<p>​	由于服务与服务之间的依赖性，故障会传播，会对整个微服务系统造成灾难性的严重后果，这就是服务故障的 “<strong>雪崩效应</strong>” 。</p>
<ul>
<li>
<p>情景1: 微服务之间相互调用,关系复杂,正常情况如下图所示:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111455359.png" alt="image-20201029125354604"></strong></p>
</li>
<li>
<p>情景2：某个时刻，服务A挂了，服务B和服务C依然在调用服务A</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456111.png" alt="image-20201029135409624"></strong></p>
</li>
<li>
<p>情景3:由于服务A挂了,导致服务C和服务B无法得到服务A的响应,这时候服务C和服务B由于大量线程积压,最终导致服务C和服务B挂掉.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456153.png" alt="image-20201029140115122"></strong></p>
</li>
<li>
<p>情景4: 相同道理,由于服务之间有关联，所以会导致整个调用链上的所有服务都挂掉.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456016.png" alt="image-20201029140259527"></strong></p>
</li>
</ul>
<p>​	服务器的雪崩效应其实就是由于某个微小的服务挂了,导致整一大片的服务都不可用.类似生活中的雪崩效应,由于落下的最后一片雪花引发了雪崩的情况.</p>
<p>​	雪崩发生的原因多种多样，有不合理的容量设计，或者是高并发下某一个方法响应变慢，亦或是某台机器的资源耗尽。我们无法完全杜绝雪崩源头的发生，只有做好足够的容错，保证在一个服务发生问题，不会影响到其它服务的正常运行。</p>
</li>
</ol>
<h2 id="62-常见容错方案">6.2 常见容错方案</h2>
<p>​	要防止雪崩的扩散，我们就要做好服务的容错，容错说白了就是保护自己不被猪队友拖垮的一些措施, 下面介绍常见的服务容错思路和组件。</p>
<p><strong>常见的容错思路</strong></p>
<p>常见的容错思路有==隔离、超时、限流、熔断、降级==这几种，下面分别介绍一下。</p>
<ul>
<li>
<p><strong>隔离机制</strong>: 比如服务A内总共有100个线程, 现在服务A可能会调用服务B,服务C,服务D.我们在服务A进行远程调用的时候,给不同的服务分配固定的线程,不会把所有线程都分配给某个微服务. 比如调用服务B分配30个线程,调用服务C分配30个线程，调用服务D分配40个线程. 这样进行资源的隔离，保证即使下游某个服务挂了，也不至于把服务A的线程消耗完。比如服务B挂了，这时候最多只会占用服务A的30个线程,服务A还有70个线程可以调用服务C和服务D.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456722.png" alt="image-20201029142100450"></strong></p>
</li>
<li>
<p><strong>超时机制</strong>: 在上游服务调用下游服务的时候，设置一个最大响应时间，如果超过这个时间，下游未作出反应，就断开请求，释放掉线程。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456667.png" alt="image-20201029143237828"></strong></p>
</li>
<li>
<p><strong>限流机制</strong>: 限流就是限制系统的输入和输出流量已达到保护系统的目的。为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456296.png" alt="image-20201029143206491"></strong></p>
</li>
<li>
<p><strong>熔断机制</strong>: 在互联网系统中，当下游服务因访问压力过大而响应变慢或失败，上游服务为了保护系统整体的可用性，可以暂时切断对下游服务的调用。这种牺牲局部，保全整体的措施就叫做熔断。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456996.png" alt="image-20201029143128555"></strong></p>
<p>服务熔断一般有三种状态：</p>
<ul>
<li>熔断关闭状态（Closed）</li>
</ul>
<p>服务没有故障时，熔断器所处的状态，对调用方的调用不做任何限制</p>
<ul>
<li>熔断开启状态（Open）</li>
</ul>
<p>后续对该服务接口的调用不再经过网络，直接执行本地的fallback方法</p>
<ul>
<li>半熔断状态（Half-Open）</li>
</ul>
<p>尝试恢复服务调用，允许有限的流量调用该服务，并监控调用成功率。如果成功率达到预期，则说明服务已恢复，进入熔断关闭状态；如果成功率仍旧很低，则重新进入熔断关闭状态。</p>
</li>
<li>
<p><strong>降级机制</strong>: 降级其实就是为服务提供一个兜底方案，一旦服务无法正常调用，就使用兜底方案。</p>
</li>
</ul>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456399.png" alt="image-20201029143456888"></strong></p>
<h2 id="63-常见的容错组件">6.3 常见的容错组件</h2>
<ul>
<li><strong>Hystrix</strong></li>
</ul>
<p>Hystrix是由Netflflix开源的一个延迟和容错库，用于隔离访问远程系统、服务或者第三方库，防止</p>
<p>级联失败，从而提升系统的可用性与容错性。</p>
<ul>
<li><strong>Resilience4J</strong></li>
</ul>
<p>Resilicence4J一款非常轻量、简单，并且文档非常清晰、丰富的熔断工具，这也是Hystrix官方推</p>
<p>荐的替代产品。不仅如此，Resilicence4j还原生支持Spring Boot 1.x/2.x，而且监控也支持和</p>
<p>prometheus等多款主流产品进行整合。</p>
<ul>
<li><strong>Sentinel</strong></li>
</ul>
<p>Sentinel 是阿里巴巴开源的一款断路器实现，本身在阿里内部已经被大规模采用，非常稳定。</p>
<h2 id="64-sentinel入门">6.4 Sentinel入门</h2>
<h3 id="641-什么是sentinel">6.4.1 什么是Sentinel</h3>
<p>Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于<strong>服务容错</strong>的综合性解决方案。它以流量为切入点, 从<strong>流量控制、熔断降级、系统负载保护</strong>等多个维度来保护服务的稳定性</p>
<p>Sentinel 具有以下特征:</p>
<ul>
<li>
<p><strong>丰富的应用场景</strong>：Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀（即突发流量控制在系统容量可以承受的范围）、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。</p>
</li>
<li>
<p><strong>完备的实时监控</strong>：Sentinel 提供了实时的监控功能。通过控制台可以看到接入应用的单台机器秒级数据, 甚至 500 台以下规模的集群的汇总运行情况。</p>
</li>
<li>
<p><strong>广泛的开源生态</strong>：Sentinel 提供开箱即用的与其它开源框架/库的整合模块, 例如与 SpringCloud、Dubbo、gRPC 的整合。只需要引入相应的依赖并进行简单的配置即可快速地接入Sentinel。</p>
</li>
</ul>
<p><strong>Sentinel分为两个部分</strong>:</p>
<ul>
<li>
<p>核心库（Java 客户端）不依赖任何框架/库,能够运行于所有 Java 运行时环境，同时对 Dubbo /Spring Cloud 等框架也有较好的支持。</p>
</li>
<li>
<p>控制台（Dashboard）基于 Spring Boot 开发，打包后可以直接运行，不需要额外的 Tomcat 等应用容器。</p>
</li>
</ul>
<h3 id="642-订单微服务集成sentinel">6.4.2 订单微服务集成Sentinel</h3>
<p>为微服务集成Sentinel非常简单, 只需要加入Sentinel的依赖即可</p>
<p>在shop-order-server项目的pom文件中添加如下依赖</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;!--sentinel组件--&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;groupId&gt;</span>com.alibaba.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-starter-alibaba-sentinel<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div><h3 id="643-安装sentinel控制台">6.4.3 安装Sentinel控制台</h3>
<p>Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能。</p>
<ol>
<li>
<p>下载jar包 <a href="https://github.com/alibaba/Sentinel/releases">https://github.com/alibaba/Sentinel/releases</a></p>
</li>
<li>
<p>启动控制台</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 直接使用jar命令启动项目(控制台本身是一个SpringBoot项目) </span>
</span></span><span style="display:flex;"><span>java -Dserver.port<span style="color:#f92672">=</span><span style="color:#ae81ff">8080</span> -Dcsp.sentinel.dashboard.server<span style="color:#f92672">=</span>localhost:8080 -Dproject.name<span style="color:#f92672">=</span>sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
</span></span></code></pre></div><ol start="3">
<li>
<p>修改shop-order-server项目中的配置文件application.yml,新增如下配置:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">sentinel</span>: 
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">transport</span>: 
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">port</span>: <span style="color:#ae81ff">9999</span> <span style="color:#75715e">#跟控制台交流的端口,随意指定一个未使用的端口即可 </span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">dashboard</span>: <span style="color:#ae81ff">localhost:8080</span> <span style="color:#75715e"># 指定控制台服务的地址</span>
</span></span></code></pre></div></li>
<li>
<p>通过浏览器访问localhost:8080 进入控制台 ( 默认用户名密码是 sentinel/sentinel )</p>
<p>注意: 默认是没显示order-service的，需要访问几次接口，然后再刷新sentinel管控台才可以看到.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456901.png" alt="image-20201029151420936"></strong></p>
</li>
</ol>
<h3 id="644-实现一个接口的限流">6.4.4 实现一个接口的限流</h3>
<p>第一步: 簇点链路&mdash;&gt;流控</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456099.png" alt="image-20201029151937258"></strong></p>
<p>第二步: 在单机阈值填写一个数值，表示每秒上限的请求数</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456459.png" alt="image-20201029152031334"></strong></p>
<p>第三步:通过控制台快速频繁访问, 观察效果</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456248.png" alt="image-20201029152401508"></strong></p>
<h3 id="645-sentinel容错的维度">6.4.5 Sentinel容错的维度</h3>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456167.png" alt="image-20201029153848900"></strong></p>
<p><strong>流量控制</strong>：流量控制在网络传输中是一个常用的概念，它用于调整网络包的数据。任意时间到来的请求往往是</p>
<p>随机不可控的，而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。</p>
<p><strong>熔断降级</strong>：当检测到调用链路中某个资源出现不稳定的表现，例如请求响应时间长或异常比例升高的时候，则</p>
<p>对这个资源的调用进行限制，让请求快速失败，避免影响到其它的资源而导致级联故障。</p>
<p><strong>系统负载保护</strong>：Sentinel 同时提供系统维度的自适应保护能力。当系统负载较高的时候，如果还持续让</p>
<p>请求进入可能会导致系统崩溃，无法响应。在集群环境下，会把本应这台机器承载的流量转发到其</p>
<p>它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候，Sentinel 提供了对应的保</p>
<p>护机制，让系统的入口流量和系统的负载达到一个平衡，保证系统在能力范围之内处理最多的请</p>
<p>求。</p>
<h3 id="646-sentinel规则种类">6.4.6 Sentinel规则种类</h3>
<p>Sentinel主要提供了这五种的流量控制，接下来我们每种都给同学们演示一下.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456727.png" alt="image-20201029160041081"></strong></p>
<h2 id="65-sentinel规则-流控">6.5 Sentinel规则-流控</h2>
<h3 id="651-流控规则">6.5.1 流控规则</h3>
<p>流量控制，其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标，当达到指定的阈值时</p>
<p>对流量进行控制，以避免被瞬时的流量高峰冲垮，从而保障应用的高可用性。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111456943.png" alt="image-20201029160919062"></strong></p>
<p><strong>资源名</strong>：唯一名称，默认是请求路径，可自定义</p>
<p><strong>针对来源</strong>：指定对哪个微服务进行限流，默认指default，意思是不区分来源，全部限制</p>
<p><strong>阈值类型/单机阈值</strong>：</p>
<ul>
<li>
<p>QPS（每秒请求数量）: 当调用该接口的QPS达到阈值的时候，进行限流</p>
</li>
<li>
<p>线程数：当调用该接口的线程数达到阈值的时候，进行限流</p>
</li>
</ul>
<p><strong>是否集群</strong>：暂不需要集群</p>
<h4 id="6511-qps流控">6.5.1.1 QPS流控</h4>
<p>前面6.4.4案例就是演示的QPS流控</p>
<h4 id="6512-线程数流控">6.5.1.2 线程数流控</h4>
<ol>
<li>
<p>删除掉之前的QPS流控，新增线程数流控</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457802.png" alt="image-20201029162926422"></strong></p>
</li>
<li>
<p>在Jmeter中新增线程</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457232.png" alt="image-20201029163205306"></strong></p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457758.png" alt="image-20201029163233714"></strong></p>
</li>
<li>
<p>访问 http://localhost:8091/sentinel2 会发现已经被限流</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457677.png" alt="image-20201029163416823"></strong></p>
</li>
</ol>
<h3 id="652-流控模式">6.5.2 流控模式</h3>
<p>点击上面设置流控规则的<strong>编辑</strong>按钮，然后在编辑页面点击<strong>高级选项</strong>，会看到有流控模式一栏。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457603.png" alt="image-20201029164212597"></strong></p>
<p>sentinel共有三种流控模式，分别是：</p>
<ul>
<li>
<p>直接（默认）：接口达到限流条件时，开启限流</p>
</li>
<li>
<p>关联：当关联的资源达到限流条件时，开启限流 [适合做应用让步]</p>
</li>
<li>
<p>链路：当从某个接口过来的资源达到限流条件时，开启限流</p>
</li>
</ul>
<h4 id="6521-直接流控模式">6.5.2.1 直接流控模式</h4>
<p>前面演示的案例就是这种.</p>
<h4 id="6522-关联流控模式">6.5.2.2 关联流控模式</h4>
<p>关联流控模式指的是，当指定接口关联的接口达到限流条件时，开启对指定接口开启限流。</p>
<p><strong>场景</strong>:当两个资源之间具有资源争抢或者依赖关系的时候，这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢，读的速度过高会影响写得速度，写的速度过高会影响读的速度。如果放任读写操作争抢资源，则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢.</p>
<ol>
<li>
<p>在SentinelController.java中增加一个方法，重启订单服务</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/sentinel3&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">sentinel3</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;sentinel3&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>配置限流规则, 将流控模式设置为关联，关联资源设置为的 /sentinel2</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457632.png" alt="image-20201029170800980"></strong></p>
</li>
<li>
<p>通过postman软件向/sentinel2连续发送请求，注意QPS一定要大于3</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457256.png" alt="image-20201029171026368"></strong></p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457680.png" alt="image-20201029171055757"></strong></p>
</li>
<li>
<p>访问/sentinel3,会发现已经被限流</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457129.png" alt="image-20201029171402061"></strong></p>
</li>
</ol>
<h4 id="6523-链路流控模式">6.5.2.3 链路流控模式</h4>
<p>链路流控模式指的是，当从某个接口过来的资源达到限流条件时，开启限流。</p>
<ol>
<li>
<p>在shop-order-server项目的application.yml文件中新增如下配置:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">sentinel</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">web-context-unify</span>: <span style="color:#66d9ef">false</span>
</span></span></code></pre></div></li>
<li>
<p>在shop-order-server项目中新增TraceServiceImpl.java</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.service.impl<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Service</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TraceServiceImpl</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@SentinelResource</span><span style="color:#f92672">(</span>value <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;tranceService&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">tranceService</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;调用tranceService方法&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>在shop-order-server项目中新增TraceController.java</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.controller<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TraceController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> TraceServiceImpl traceService<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/trace1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">trace1</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        traceService<span style="color:#f92672">.</span><span style="color:#a6e22e">tranceService</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;trace1&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/trace2&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">trace2</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        traceService<span style="color:#f92672">.</span><span style="color:#a6e22e">tranceService</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;trace2&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>重新启动订单服务并添加链路流控规则</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457036.png" alt="image-20201029175454431"></strong></p>
</li>
<li>
<p>分别通过 /trace1 和 /trace2 访问, 发现/trace1没问题, /trace2的被限流了</p>
</li>
</ol>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457302.png" alt="image-20201029175555499"></strong></p>
<h3 id="653-流控效果">6.5.3 流控效果</h3>
<ul>
<li>
<p><strong>快速失败（默认）</strong>: 直接失败，抛出异常，不做任何额外的处理，是最简单的效果</p>
</li>
<li>
<p><strong>Warm Up</strong>：它从开始阈值到最大QPS阈值会有一个缓冲阶段，一开始的阈值是最大QPS阈值的1/3，然后慢慢增长，直到最大阈值，适用于将突然增大的流量转换为缓步增长的场景。</p>
</li>
<li>
<p><strong>排队等待</strong>：让请求以均匀的速度通过，单机阈值为每秒通过数量，其余的排队等待； 它还会让设置一个超时时间，当请求超过超时间时间还未处理，则会被丢弃。</p>
</li>
</ul>
<h2 id="66-sentinel规则-降级">6.6 Sentinel规则-降级</h2>
<p>降级规则就是设置当满足什么条件的时候，对服务进行降级。Sentinel提供了三个衡量条件：</p>
<ul>
<li><strong>慢调用比例</strong>: 选择以慢调用比例作为阈值，需要设置允许的慢调用 RT（即最大的响应时间），请求的响应时间大于该值则统计为慢调用。当单位统计时长内请求数目大于设置的最小请求数目，并且慢调用的比例大于阈值，则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态（HALF-OPEN 状态），若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断，若大于设置的慢调用 RT 则会再次被熔断。</li>
<li><strong>异常比例</strong>: 当单位统计时长内请求数目大于设置的最小请求数目，并且异常的比例大于阈值，则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态（HALF-OPEN 状态），若接下来的一个请求成功完成（没有错误）则结束熔断，否则会再次被熔断。异常比率的阈值范围是 <code>[0.0, 1.0]</code>，代表 0% - 100%。</li>
<li><strong>异常数</strong>：当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态（HALF-OPEN 状态），若接下来的一个请求成功完成（没有错误）则结束熔断，否则会再次被熔断。</li>
</ul>
<h3 id="661-慢调用比例案例">6.6.1 慢调用比例案例</h3>
<ol>
<li>
<p>在shop-order-server项目中新增FallBackController.java类,代码如下:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.controller<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">FallBackController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/fallBack1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">fallBack1</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;fallBack1执行业务逻辑&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">//模拟业务耗时
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>            TimeUnit<span style="color:#f92672">.</span><span style="color:#a6e22e">SECONDS</span><span style="color:#f92672">.</span><span style="color:#a6e22e">sleep</span><span style="color:#f92672">(</span>1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>InterruptedException e<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            e<span style="color:#f92672">.</span><span style="color:#a6e22e">printStackTrace</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;fallBack1&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>新增降级规则:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457989.png" alt="image-20201030094205307"></strong></p>
<p>上面配置表示，如果在1S之内,有【超过1个的请求】且这些请求中【响应时间&gt;最大RT】的【请求数量比例&gt;10%】，就会触发熔断，在接下来的10s之内都不会调用真实方法，直接走降级方法。</p>
<p>比如: 最大RT=900,比例阈值=0.1,熔断时长=10,最小请求数=10</p>
<ul>
<li>
<p>情况1: 1秒内的有20个请求，只有10个请求响应时间&gt;900ms, 那慢调用比例=0.5，这种情况就会触发熔断</p>
</li>
<li>
<p>情况2: 1秒内的有20个请求，只有1个请求响应时间&gt;900ms, 那慢调用比例=0.05，这种情况不会触发熔断</p>
</li>
<li>
<p>情况3: 1秒内的有8个请求，只有6个请求响应时间&gt;900ms, 那慢调用比例=0.75，这种情况不会触发熔断，因为最小请求数这个条件没有满足.</p>
</li>
</ul>
<p><strong>注意</strong>: 我们做实验的时候把最小请求数设置为1，因为在1秒内，手动操作很难在1s内发两个请求过去，所以要做出效果,最好把最小请求数设置为1。</p>
</li>
</ol>
<h3 id="662-异常比例案例">6.6.2 异常比例案例</h3>
<ol>
<li>
<p>在shop-order-server项目的FallBackController.java类新增fallBack2方法:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">int</span> i<span style="color:#f92672">=</span>0<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/fallBack2&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">fallBack2</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>	log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;fallBack2执行业务逻辑&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">//模拟出现异常，异常比例为33%
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">if</span><span style="color:#f92672">(++</span>i<span style="color:#f92672">%</span>3<span style="color:#f92672">==</span>0<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> RuntimeException<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;fallBack2&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>新增降级规则:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111457179.png" alt="image-20201030100912417"></strong></p>
<p>上面配置表示，在1s之内，,有【超过3个的请求】，异常比例30%的情况下，触发熔断，熔断时长为10s.</p>
</li>
</ol>
<h3 id="633-异常数案例">6.3.3 异常数案例</h3>
<ol>
<li>
<p>在shop-order-server项目的FallBackController.java类新增fallBack3方法:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/fallBack3&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">fallBack3</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>	log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;fallBack3执行业务逻辑&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;czh0123&#34;</span><span style="color:#f92672">.</span><span style="color:#a6e22e">equals</span><span style="color:#f92672">(</span>name<span style="color:#f92672">)){</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> RuntimeException<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;fallBack3&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>新增降级规则</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458459.png" alt="image-20201030102109574"></strong></p>
<p>上面配置表示，在1s之内，,有【超过3个的请求】，请求中超过2个请求出现异常就会触发熔断，熔断时长为10s</p>
</li>
</ol>
<h2 id="67-sentinel规则-热点">6.7 Sentinel规则-热点</h2>
<p>何为热点？热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据，并对其访问进行限制。比如：</p>
<ul>
<li>商品 ID 为参数，统计一段时间内最常购买的商品 ID 并进行限制</li>
<li>用户 ID 为参数，针对一段时间内频繁访问的用户 ID 进行限制</li>
</ul>
<p>热点参数限流会统计传入参数中的热点参数，并根据配置的限流阈值与模式，对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制，仅对包含热点参数的资源调用生效。</p>
<ol>
<li>
<p>在shop-order-server项目中新增HotSpotController.java,代码如下:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.controller<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">HotSpotController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/hotSpot1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@SentinelResource</span><span style="color:#f92672">(</span>value <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;hotSpot1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">hotSpot1</span><span style="color:#f92672">(</span>Long productId<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;访问编号为:{}的商品&#34;</span><span style="color:#f92672">,</span>productId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;hotSpot1&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>注意:一定需要在请求方法上贴@SentinelResource直接，否则热点规则无效</p>
</li>
<li>
<p>新增热点规则:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458973.png" alt="image-20201030104511784"></strong></p>
</li>
<li>
<p>在热点规则中编辑规则,在编辑之前一定要先访问一下/hotSpot1,不然参数规则无法新增.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458826.png" alt="image-20201030104633745"></strong></p>
</li>
<li>
<p>新增参数规则:</p>
<p><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458326.png" alt="1625630523922"></p>
</li>
<li>
<p>点击保存，可以看到已经新增了参数规则.</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458204.png" alt="image-20201030104957789"></strong></p>
</li>
<li>
<p>访问http://localhost:8091/hotSpot?productId=1 访问会降级</p>
<p>访问http://localhost:8091/hotSpot?productId=2 访问不会降级</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458253.png" alt="image-20201030105114878"></strong></p>
</li>
</ol>
<h2 id="68-sentinel规则-授权">6.8 Sentinel规则-授权</h2>
<p>很多时候，我们需要根据调用来源来判断该次请求是否允许放行，这时候可以使用 Sentinel 的来源访问控制（黑白名单控制）的功能。来源访问控制根据资源的请求来源（<code>origin</code>）限制资源是否通过，若配置白名单则只有请求来源位于白名单内时才可通过；若配置黑名单则请求来源位于黑名单时不通过，其余的请求通过。</p>
<ol>
<li>
<p>在shop-order-server中新建RequestOriginParserDefinition.java,定义请求来源如何获取</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Component</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">RequestOriginParserDefinition</span> <span style="color:#66d9ef">implements</span> RequestOriginParser <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">parseOrigin</span><span style="color:#f92672">(</span>HttpServletRequest request<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">         *  定义从请求的什么地方获取来源信息
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">         *  比如我们可以要求所有的客户端需要在请求头中携带来源信息
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">         */</span>
</span></span><span style="display:flex;"><span>        String serviceName <span style="color:#f92672">=</span> request<span style="color:#f92672">.</span><span style="color:#a6e22e">getParameter</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;serviceName&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> serviceName<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>在shop-order-server中新建AuthController.java,代码如下:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AuthController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/auth1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">auth1</span><span style="color:#f92672">(</span>String serviceName<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;应用:{},访问接口&#34;</span><span style="color:#f92672">,</span>serviceName<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;auth1&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>新增授权规则</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458265.png" alt="image-20201030110821985"></strong></p>
</li>
<li>
<p>访问测试</p>
<p>访问http://localhost:8091/auth1?serviceName=pc 不能访问</p>
<p>访问http://localhost:8091/auth1?serviceName=app 可以访问</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458898.png" alt="image-20201030110934370"></strong></p>
</li>
</ol>
<h2 id="69-sentinel规则-系统规则">6.9 Sentinel规则-系统规则</h2>
<p>系统保护规则是从应用级别的入口流量进行控制，从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标，让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。</p>
<p>系统保护规则是应用整体维度的，而不是资源维度的，并且<strong>仅对入口流量生效</strong>。入口流量指的是进入应用的流量（<code>EntryType.IN</code>），比如 Web 服务或 Dubbo 服务端接收的请求，都属于入口流量。</p>
<p>系统规则支持以下的模式：</p>
<ul>
<li><strong>Load 自适应</strong>（仅对 Linux/Unix-like 机器生效）：系统的 load 作为启发指标，进行自适应系统保护。当系统 load 超过设定的启发值，且系统当前的并发线程数超过估算的系统容量时才会触发系统保护（BBR 阶段）。系统容量由系统的 <code>maxQps * minRt</code> 估算得出。设定参考值一般是 <code>CPU cores * 2.5</code>。</li>
<li><strong>CPU usage</strong>（1.5.0+ 版本）：当系统 CPU 使用率超过阈值即触发系统保护（取值范围 0.0-1.0），比较灵敏。</li>
<li><strong>平均 RT</strong>：当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护，单位是毫秒。</li>
<li><strong>并发线程数</strong>：当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。</li>
<li><strong>入口 QPS</strong>：当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。</li>
</ul>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111458898.png" alt="image-20201030111407594"></strong></p>
<h2 id="610--sentinel-自定义异常返回">6.10  Sentinel 自定义异常返回</h2>
<p>当前面设定的规则没有满足是，我们可以自定义异常返回.</p>
<ul>
<li>
<p>FlowException 限流异常</p>
</li>
<li>
<p>DegradeException 降级异常</p>
</li>
<li>
<p>ParamFlowException 参数限流异常</p>
</li>
<li>
<p>AuthorityException 授权异常</p>
</li>
<li>
<p>SystemBlockException 系统负载异常</p>
</li>
</ul>
<p>在shop-order-server项目中定义异常返回处理类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.error<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Component</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ExceptionHandlerPage</span> <span style="color:#66d9ef">implements</span> BlockExceptionHandler <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">handle</span><span style="color:#f92672">(</span>HttpServletRequest request<span style="color:#f92672">,</span> HttpServletResponse response<span style="color:#f92672">,</span> BlockException e<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        response<span style="color:#f92672">.</span><span style="color:#a6e22e">setContentType</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;application/json;charset=utf-8&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        ResultData data <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>e <span style="color:#66d9ef">instanceof</span> FlowException<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            data <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ResultData<span style="color:#f92672">(-</span>1<span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;接口被限流了&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>e <span style="color:#66d9ef">instanceof</span> DegradeException<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            data <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ResultData<span style="color:#f92672">(-</span>2<span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;接口被降级了&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span><span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>e <span style="color:#66d9ef">instanceof</span> ParamFlowException<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            data <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ResultData<span style="color:#f92672">(-</span>3<span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;参数限流异常&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span><span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>e <span style="color:#66d9ef">instanceof</span> AuthorityException<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            data <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ResultData<span style="color:#f92672">(-</span>4<span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;授权异常&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span><span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>e <span style="color:#66d9ef">instanceof</span> SystemBlockException<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            data <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ResultData<span style="color:#f92672">(-</span>5<span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;接口被降级了...&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        response<span style="color:#f92672">.</span><span style="color:#a6e22e">getWriter</span><span style="color:#f92672">().</span><span style="color:#a6e22e">write</span><span style="color:#f92672">(</span>JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>data<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Data</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@AllArgsConstructor</span><span style="color:#75715e">//全参构造
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">@NoArgsConstructor</span><span style="color:#75715e">//无参构造
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ResultData</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">int</span> code<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String message<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h2 id="611-sentinelresource的使用">6.11 @SentinelResource的使用</h2>
<p>在定义了资源点之后，我们可以通过Dashboard来设置限流和降级策略来对资源点进行保护。同时还能</p>
<p>通过@SentinelResource来指定出现异常时的处理策略。</p>
<p>@SentinelResource 用于定义资源，并提供可选的异常处理和 fallback 配置项。</p>
<p>其主要参数如下:</p>
<table>
<thead>
<tr>
<th style="text-align:left">属性</th>
<th>作用</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">value</td>
<td>资源名称，必需项（不能为空）</td>
</tr>
<tr>
<td style="text-align:left">entryType</td>
<td>entry 类型，可选项（默认为 <code>EntryType.OUT</code>）</td>
</tr>
<tr>
<td style="text-align:left">blockHandler<code>/</code>blockHandlerClass</td>
<td><code>blockHandler</code> 对应处理 <code>BlockException</code> 的函数名称，可选项。blockHandler 函数访问范围需要是 <code>public</code>，返回类型需要与原方法相匹配，参数类型需要和原方法相匹配并且最后加一个额外的参数，类型为 <code>BlockException</code>。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 <code>blockHandlerClass</code> 为对应的类的 <code>Class</code> 对象，注意对应的函数必需为 static 函数，否则无法解析。</td>
</tr>
<tr>
<td style="text-align:left">fallback<code>/</code>fallbackClass</td>
<td>fallback 函数名称，可选项，用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常（除了 <code>exceptionsToIgnore</code> 里面排除掉的异常类型）进行处理。fallback 函数签名和位置要求：<!-- raw HTML omitted -->1. 返回值类型必须与原函数返回值类型一致； <!-- raw HTML omitted -->2.方法参数列表需要和原函数一致，或者可以额外多一个 <code>Throwable</code> 类型的参数用于接收对应的异常。<!-- raw HTML omitted -->3.fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 <code>fallbackClass</code> 为对应的类的 <code>Class</code> 对象，注意对应的函数必需为 static 函数，否则无法解析。</td>
</tr>
<tr>
<td style="text-align:left">defaultFallback</td>
<td>默认的 fallback 函数名称，可选项，通常用于通用的 fallback 逻辑（即可以用于很多服务或方法）。默认 fallback 函数可以针对所有类型的异常（除了 <code>exceptionsToIgnore</code> 里面排除掉的异常类型）进行处理。若同时配置了 fallback 和 defaultFallback，则只有 fallback 会生效。defaultFallback 函数签名要求：<!-- raw HTML omitted -->1. 返回值类型必须与原函数返回值类型一致；<!-- raw HTML omitted -->2. 方法参数列表需要为空，或者可以额外多一个 <code>Throwable</code> 类型的参数用于接收对应的异常。 <!-- raw HTML omitted -->3. defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 <code>fallbackClass</code> 为对应的类的 <code>Class</code> 对象，注意对应的函数必需为 static 函数，否则无法解析。</td>
</tr>
<tr>
<td style="text-align:left">exceptionsToIgnore</td>
<td>用于指定哪些异常被排除掉，不会计入异常统计中，也不会进入 fallback 逻辑中，而是会原样抛出。</td>
</tr>
</tbody>
</table>
<p><strong>定义限流和降级后的处理方法</strong></p>
<p>直接将限流和降级方法定义在方法中</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.controller<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Slf4j</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AnnoController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/anno1&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@SentinelResource</span><span style="color:#f92672">(</span>value <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;anno1&#34;</span><span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            blockHandler<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;anno1BlockHandler&#34;</span><span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            fallback <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;anno1Fallback&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">anno1</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;czh0123&#34;</span><span style="color:#f92672">.</span><span style="color:#a6e22e">equals</span><span style="color:#f92672">(</span>name<span style="color:#f92672">)){</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> RuntimeException<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;anno1&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">anno1BlockHandler</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">,</span>BlockException ex<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">error</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;{}&#34;</span><span style="color:#f92672">,</span> ex<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;接口被限流或者降级了&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//Throwable时进入的方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">anno1Fallback</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">,</span>Throwable throwable<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        log<span style="color:#f92672">.</span><span style="color:#a6e22e">error</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;{}&#34;</span><span style="color:#f92672">,</span> throwable<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;接口发生异常了&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h2 id="612-sentinel规则持久化">6.12 Sentinel规则持久化</h2>
<p>​	通过前面的讲解，我们已经知道，可以通过Dashboard来为每个Sentinel客户端设置各种各样的规</p>
<p>则，但是这里有一个问题，就是这些规则默认是存放在内存中，极不稳定，所以需要将其持久化。</p>
<p>​	本地文件数据源会定时轮询文件的变更，读取规则。这样我们既可以在应用本地直接修改文件来更</p>
<p>新规则，也可以通过 Sentinel 控制台推送规则。以本地文件数据源为例，推送过程如下图所示：</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111459121.png" alt="image-20201030135911029"></strong></p>
<p>首先 Sentinel 控制台通过 API 将规则推送至客户端并更新到内存中，接着注册的写数据源会将新的</p>
<p>规则保存到本地的文件中。</p>
<ol>
<li>
<p>编写处理类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.sentinel<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">FilePersistence</span> <span style="color:#66d9ef">implements</span> InitFunc <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Value</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;${spring.application.name}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String appcationName<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">init</span><span style="color:#f92672">()</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        String ruleDir <span style="color:#f92672">=</span> System<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;user.home&#34;</span><span style="color:#f92672">)</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/sentinel-rules/&#34;</span> <span style="color:#f92672">+</span> appcationName<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        String flowRulePath <span style="color:#f92672">=</span> ruleDir <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/flow-rule.json&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        String degradeRulePath <span style="color:#f92672">=</span> ruleDir <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/degrade-rule.json&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        String systemRulePath <span style="color:#f92672">=</span> ruleDir <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/system-rule.json&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        String authorityRulePath <span style="color:#f92672">=</span> ruleDir <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/authority-rule.json&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        String paramFlowRulePath <span style="color:#f92672">=</span> ruleDir <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/param-flow-rule.json&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">mkdirIfNotExits</span><span style="color:#f92672">(</span>ruleDir<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">createFileIfNotExits</span><span style="color:#f92672">(</span>flowRulePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">createFileIfNotExits</span><span style="color:#f92672">(</span>degradeRulePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">createFileIfNotExits</span><span style="color:#f92672">(</span>systemRulePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">createFileIfNotExits</span><span style="color:#f92672">(</span>authorityRulePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">createFileIfNotExits</span><span style="color:#f92672">(</span>paramFlowRulePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 流控规则
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ReadableDataSource<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>FlowRule<span style="color:#f92672">&gt;&gt;</span> flowRuleRDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileRefreshableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                flowRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                flowRuleListParser
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        FlowRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">register2Property</span><span style="color:#f92672">(</span>flowRuleRDS<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        WritableDataSource<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>FlowRule<span style="color:#f92672">&gt;&gt;</span> flowRuleWDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileWritableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                flowRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">this</span><span style="color:#f92672">::</span>encodeJson
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        WritableDataSourceRegistry<span style="color:#f92672">.</span><span style="color:#a6e22e">registerFlowDataSource</span><span style="color:#f92672">(</span>flowRuleWDS<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 降级规则
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ReadableDataSource<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>DegradeRule<span style="color:#f92672">&gt;&gt;</span> degradeRuleRDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileRefreshableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                degradeRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                degradeRuleListParser
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        DegradeRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">register2Property</span><span style="color:#f92672">(</span>degradeRuleRDS<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        WritableDataSource<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>DegradeRule<span style="color:#f92672">&gt;&gt;</span> degradeRuleWDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileWritableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                degradeRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">this</span><span style="color:#f92672">::</span>encodeJson
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        WritableDataSourceRegistry<span style="color:#f92672">.</span><span style="color:#a6e22e">registerDegradeDataSource</span><span style="color:#f92672">(</span>degradeRuleWDS<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 系统规则
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ReadableDataSource<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>SystemRule<span style="color:#f92672">&gt;&gt;</span> systemRuleRDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileRefreshableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                systemRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                systemRuleListParser
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        SystemRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">register2Property</span><span style="color:#f92672">(</span>systemRuleRDS<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        WritableDataSource<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>SystemRule<span style="color:#f92672">&gt;&gt;</span> systemRuleWDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileWritableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                systemRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">this</span><span style="color:#f92672">::</span>encodeJson
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        WritableDataSourceRegistry<span style="color:#f92672">.</span><span style="color:#a6e22e">registerSystemDataSource</span><span style="color:#f92672">(</span>systemRuleWDS<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 授权规则
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ReadableDataSource<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>AuthorityRule<span style="color:#f92672">&gt;&gt;</span> authorityRuleRDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileRefreshableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                authorityRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                authorityRuleListParser
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        AuthorityRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">register2Property</span><span style="color:#f92672">(</span>authorityRuleRDS<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        WritableDataSource<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>AuthorityRule<span style="color:#f92672">&gt;&gt;</span> authorityRuleWDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileWritableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                authorityRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">this</span><span style="color:#f92672">::</span>encodeJson
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        WritableDataSourceRegistry<span style="color:#f92672">.</span><span style="color:#a6e22e">registerAuthorityDataSource</span><span style="color:#f92672">(</span>authorityRuleWDS<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 热点参数规则
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ReadableDataSource<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>ParamFlowRule<span style="color:#f92672">&gt;&gt;</span> paramFlowRuleRDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileRefreshableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                paramFlowRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                paramFlowRuleListParser
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        ParamFlowRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">register2Property</span><span style="color:#f92672">(</span>paramFlowRuleRDS<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        WritableDataSource<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>ParamFlowRule<span style="color:#f92672">&gt;&gt;</span> paramFlowRuleWDS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileWritableDataSource<span style="color:#f92672">&lt;&gt;(</span>
</span></span><span style="display:flex;"><span>                paramFlowRulePath<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">this</span><span style="color:#f92672">::</span>encodeJson
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        ModifyParamFlowRulesCommandHandler<span style="color:#f92672">.</span><span style="color:#a6e22e">setWritableDataSource</span><span style="color:#f92672">(</span>paramFlowRuleWDS<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Converter<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>FlowRule<span style="color:#f92672">&gt;&gt;</span> flowRuleListParser <span style="color:#f92672">=</span> source <span style="color:#f92672">-&gt;</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">parseObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>            source<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">new</span> TypeReference<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>FlowRule<span style="color:#f92672">&gt;&gt;()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Converter<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>DegradeRule<span style="color:#f92672">&gt;&gt;</span> degradeRuleListParser <span style="color:#f92672">=</span> source <span style="color:#f92672">-&gt;</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">parseObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>            source<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">new</span> TypeReference<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>DegradeRule<span style="color:#f92672">&gt;&gt;()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Converter<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>SystemRule<span style="color:#f92672">&gt;&gt;</span> systemRuleListParser <span style="color:#f92672">=</span> source <span style="color:#f92672">-&gt;</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">parseObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>            source<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">new</span> TypeReference<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>SystemRule<span style="color:#f92672">&gt;&gt;()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Converter<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>AuthorityRule<span style="color:#f92672">&gt;&gt;</span> authorityRuleListParser <span style="color:#f92672">=</span> source <span style="color:#f92672">-&gt;</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">parseObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>            source<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">new</span> TypeReference<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>AuthorityRule<span style="color:#f92672">&gt;&gt;()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Converter<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> List<span style="color:#f92672">&lt;</span>ParamFlowRule<span style="color:#f92672">&gt;&gt;</span> paramFlowRuleListParser <span style="color:#f92672">=</span> source <span style="color:#f92672">-&gt;</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">parseObject</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>            source<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">new</span> TypeReference<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>ParamFlowRule<span style="color:#f92672">&gt;&gt;()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">mkdirIfNotExits</span><span style="color:#f92672">(</span>String filePath<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> IOException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        File file <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> File<span style="color:#f92672">(</span>filePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(!</span>file<span style="color:#f92672">.</span><span style="color:#a6e22e">exists</span><span style="color:#f92672">())</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            file<span style="color:#f92672">.</span><span style="color:#a6e22e">mkdirs</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">createFileIfNotExits</span><span style="color:#f92672">(</span>String filePath<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> IOException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        File file <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> File<span style="color:#f92672">(</span>filePath<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(!</span>file<span style="color:#f92672">.</span><span style="color:#a6e22e">exists</span><span style="color:#f92672">())</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            file<span style="color:#f92672">.</span><span style="color:#a6e22e">createNewFile</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#f92672">&lt;</span>T<span style="color:#f92672">&gt;</span> String <span style="color:#a6e22e">encodeJson</span><span style="color:#f92672">(</span>T t<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> JSON<span style="color:#f92672">.</span><span style="color:#a6e22e">toJSONString</span><span style="color:#f92672">(</span>t<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>添加配置</p>
<p>在<code>resources</code>下创建配置目录 <code>META-INF/services</code> ,然后添加文件 <code>com.alibaba.csp.sentinel.init.InitFunc</code></p>
<p>在文件中添加配置类的全路径</p>
<p><code>cn.czh0123.sentinel.FilePersistence</code></p>
</li>
</ol>
<h2 id="613-feign整合sentinel">6.13 Feign整合Sentinel</h2>
<ol>
<li>
<p>在shop-order-server项目的配置文件中开启feign对Sentinel的支持</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">feign</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">sentinel</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div></li>
<li>
<p>创建容错类</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Component</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ProductFeignFallBack</span> <span style="color:#66d9ef">implements</span> ProductFeignApi <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Product <span style="color:#a6e22e">findByPid</span><span style="color:#f92672">(</span>Long pid<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Product product <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Product<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        product<span style="color:#f92672">.</span><span style="color:#a6e22e">setPid</span><span style="color:#f92672">(-</span>1L<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        product<span style="color:#f92672">.</span><span style="color:#a6e22e">setPname</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;兜底数据&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        product<span style="color:#f92672">.</span><span style="color:#a6e22e">setPprice</span><span style="color:#f92672">(</span>0<span style="color:#f92672">.</span><span style="color:#a6e22e">0</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> product<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><ol start="3">
<li>
<p>在feign接口中定义容错类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@FeignClient</span><span style="color:#f92672">(</span>name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;product-service&#34;</span><span style="color:#f92672">,</span>fallback <span style="color:#f92672">=</span> ProductFeignFallBack<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">ProductFeignApi</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/product/{pid}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Product <span style="color:#a6e22e">findByPid</span><span style="color:#f92672">(</span><span style="color:#a6e22e">@PathVariable</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;pid&#34;</span><span style="color:#f92672">)</span> Long pid<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>停止所有 商品服务,重启 shop-order 服务,访问请求,观察容错效果</p>
</li>
</ol>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111459330.png" alt="image-20201030141556327"></strong></p>
<p>可能上面的案例并不是特别恰当，我们只是通过案例来演示Feign集成Sentinel实现降级的效果. 接下来我们具体更贴切的案例来讲解Feign降级的作用.</p>
<p>比如我们在购物的时候，查看商品详情页面的时候，里面包含库存信息,商品详情信息,评论信息，这个需求包含的微服务如下:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111459887.png" alt="image-20201030142332530"></strong></p>
<p>假设现在评论服务宕机了,那是不是意味用户发出查看商品请求也无法正常显示了，商品都看不到了，那用户也无法进行下单的操作了. 但是对于用户来说，评论看不到并不影响他购物，所以这时候我们应该对评论服务进行及·降级处理，返回一个兜底数据(空数据)，这样用户的查看商品请求能正常显示，只是评论数据看不到而已，这样的话，用户的下单请求也不会受到影响.</p>

    <h4><a href="https://czh-dev.gitee.io/czh-blog.gitee.io/">Back to Home</a></h4>
  </div>

  <div class="span3 bs-docs-sidebar" style="position:fixed;right: 40px;top: 50px;">
    <h1>catalogue</h1>
    <ul class="nav nav-list bs-docs-sidenav">
      <div class="toc-div">
        <nav id="TableOfContents">
  <ul>
    <li><a href="#61-高并发带来的问题">6.1 高并发带来的问题</a></li>
    <li><a href="#62-服务器雪崩效应">6.2 服务器雪崩效应</a></li>
    <li><a href="#62-常见容错方案">6.2 常见容错方案</a></li>
    <li><a href="#63-常见的容错组件">6.3 常见的容错组件</a></li>
    <li><a href="#64-sentinel入门">6.4 Sentinel入门</a>
      <ul>
        <li><a href="#641-什么是sentinel">6.4.1 什么是Sentinel</a></li>
        <li><a href="#642-订单微服务集成sentinel">6.4.2 订单微服务集成Sentinel</a></li>
        <li><a href="#643-安装sentinel控制台">6.4.3 安装Sentinel控制台</a></li>
        <li><a href="#644-实现一个接口的限流">6.4.4 实现一个接口的限流</a></li>
        <li><a href="#645-sentinel容错的维度">6.4.5 Sentinel容错的维度</a></li>
        <li><a href="#646-sentinel规则种类">6.4.6 Sentinel规则种类</a></li>
      </ul>
    </li>
    <li><a href="#65-sentinel规则-流控">6.5 Sentinel规则-流控</a>
      <ul>
        <li><a href="#651-流控规则">6.5.1 流控规则</a></li>
        <li><a href="#652-流控模式">6.5.2 流控模式</a></li>
        <li><a href="#653-流控效果">6.5.3 流控效果</a></li>
      </ul>
    </li>
    <li><a href="#66-sentinel规则-降级">6.6 Sentinel规则-降级</a>
      <ul>
        <li><a href="#661-慢调用比例案例">6.6.1 慢调用比例案例</a></li>
        <li><a href="#662-异常比例案例">6.6.2 异常比例案例</a></li>
        <li><a href="#633-异常数案例">6.3.3 异常数案例</a></li>
      </ul>
    </li>
    <li><a href="#67-sentinel规则-热点">6.7 Sentinel规则-热点</a></li>
    <li><a href="#68-sentinel规则-授权">6.8 Sentinel规则-授权</a></li>
    <li><a href="#69-sentinel规则-系统规则">6.9 Sentinel规则-系统规则</a></li>
    <li><a href="#610--sentinel-自定义异常返回">6.10  Sentinel 自定义异常返回</a></li>
    <li><a href="#611-sentinelresource的使用">6.11 @SentinelResource的使用</a></li>
    <li><a href="#612-sentinel规则持久化">6.12 Sentinel规则持久化</a></li>
    <li><a href="#613-feign整合sentinel">6.13 Feign整合Sentinel</a></li>
  </ul>
</nav>
      </div>
    </ul>
  </div>

</div>
<script src="https://cdn.jsdelivr.net/npm/gumshoejs@5.1.2/dist/gumshoe.min.js"></script>
<script>
  var spy = new Gumshoe('#TableOfContents a', {
    nested: true,
    nestedClass: 'active'
  });
</script>
<style>
   
  #TableOfContents li,
  #TableOfContents ul {
    list-style-type: none;
  }

  #TableOfContents ul {
    padding-left: 0px;
  }

  #TableOfContents li>a {
    display: block;
    padding: 4px 20px;
    font-size: 95%;
    color: #000000;
  }

  #TableOfContents li>a:hover,
  #TableOfContents li>a:focus {
    padding-left: 19px;
    color: #3A6bA5;
    text-decoration: none;
    background-color: transparent;
    border-left: 1px solid #3A6bA5;
  }

  #TableOfContents li.active>a,
  #TableOfContents li.active>a:hover,
  #TableOfContents li.active>a:focus {
    padding-left: 18px;
    font-weight: bold;
    color: #3A6bA5;
    background-color: transparent;
    border-left: 2px solid #3A6bA5;
  }

   
  #TableOfContents li>ul {
    padding-bottom: 10px;
  }

  #TableOfContents li li>a {
    padding-top: 1px;
    padding-bottom: 1px;
    padding-left: 30px;
    font-size: 14px;
    font-weight: normal;
  }

  #TableOfContents li li>a:hover,
  #TableOfContents li li>a:focus {
    padding-left: 29px;
  }

  #TableOfContents li li.active>a,
  #TableOfContents li li.active>a:hover,
  #TableOfContents li li.active>a:focus {
    padding-left: 28px;
    font-weight: 500;
  }

  #TableOfContents .nav-link.active+ul {
    display: block;
  }

  #TableOfContents li>ul {
    display: none;
  }

  #TableOfContents li.active>ul {
    display: inherit;
  }

  .toc-div {
    position: -webkit-sticky;
     
    position: sticky;
     
    top: 20px;
  }
</style>


        </div><footer class="container">
    <hr class="soften">
    <p>
    <a href="https://space.bilibili.com/1799809923">Love eating fried pork ribs</a> | 

&copy; 
<a href="http://jmf-portfolio.netlify.com" target="_blank">
    JM Fergeau
</a>
<span id="thisyear">2023</span>

    | My site


        | Built on <a href="//gohugo.io" target="_blank">Hugo</a>

</p>
    <p class="text-center">
        <a href="https://facebook.com">Facebook</a> 
        <a href="https://twitter.com">Twitter</a> 
        <a href="https://linkedin.com">Linkedin</a> 
        <a href="https://github.com">GitHub</a> 
        <a href="https://gitlab.com">GitLab</a>
    </p>
</footer>

</body><link rel="stylesheet" href="/czh-blog.gitee.io/css/bootstrap.css">
<link rel="stylesheet" href="/czh-blog.gitee.io/css/bootstrap-responsive.css">
<link rel="stylesheet" href="/czh-blog.gitee.io/css/style.css">

<script src="/czh-blog.gitee.io/js/jquery.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-386.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-transition.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-alert.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-modal.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-dropdown.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-scrollspy.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-tab.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-tooltip.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-popover.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-button.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-collapse.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-carousel.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-typeahead.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-affix.js"></script>
<script>
    _386 = { 
        fastLoad: false ,
        onePass: false , 
        speedFactor: 1 
    };

    
    function ThisYear() {
        document.getElementById('thisyear').innerHTML = new Date().getFullYear();
    };
</script>
</html>
